<?php


namespace App\Service;

use RuntimeException;

class UrlCrypt {

    private $key;
    private $timeDelay;

    public function __construct() {
        $this->key = config('app.urlcryptkey');
        if (empty($this->key)) {
            throw new RuntimeException('URL加密密钥未定义');
        }
        //加密串有效期延迟，防止不同服务器之间的时间戳有延迟，如11:00 过期，实际校验时会加上这个timeDelay来计算
        $this->timeDelay = 3600;
    }

    /**
     * 生成加密密钥
     * @param array $params
     * @param int $expire
     * @return string
     */
    public function generateToken(array $params, int $expire = 0) {
        if ($expire > 0) {
            $params['cryptexpire'] = time() + $expire;
        } else {
            $params['cryptexpire'] = 0;
        }
        return $this->getCryptToken($params);
    }

    /**
     * 判断加密密钥是否相同
     * @param array $params
     * @param $token
     * @return bool
     */
    public function checkUrlToken(array $params, string $token) {
        $decodeToken = base64_decode($token);
        $pointPos = strripos($decodeToken, '.');
        $expire = substr($decodeToken, $pointPos + 1);
        $params['cryptexpire'] = $expire;
        if ($token !== $this->getCryptToken($params)) {
            return false;
        }
        if ($expire > 0 && ($expire + $this->timeDelay) < time()) {
            return false;
        }
        return true;
    }

    /**
     * 生成加密串
     * @param $params
     * @return string
     */
    protected function getCryptToken($params) {
        ksort($params);
        $paramStr = http_build_query($params);
        return base64_encode(md5($paramStr . $this->key) . '.' . $params['cryptexpire']);
    }
}